#include <Wire.h>

#include <Max3421e.h>
#include <Usb.h>
#include <AndroidAccessory.h>

AndroidAccessory acc("isis re-direct",
"DreamWaver",
"DreamWaver Board",
"1.0",
"http://isisredirect.blogspot.com/",
"0000000012345679");

// Dream Waver Board mode
#define  DWSELFCHECK  0
#define  DWAUTOPLAY  1
#define  MANUALPLAY  2
#define  RECORDPALY  3
#define  DWSTOP  4

// channel command
#define  DWTURNON  0
#define  DWTURNOFF  1
#define  DWCHANGEMODE  2
#define  DWMUTE  3
#define  DWUNMUTE  4
#define  DWSETCHANNELFEREQ 5

// channel state
#define  DWON      1
#define  DWOFF     0

//  Dream Waver Board Mode
byte  gMode;

// channel state 
byte  gChannelStates[16];
int gFreqOfChannel[16] ;
int gPulseTimeOfChannel[16];
int gRetainTimeOfChannel[16];
unsigned long gDuTimeOfChannel[16];
unsigned long gRetainDuTimeOfChannel[16];
boolean  gMutedOfChannel[16];


#define  PCPULSELENGTH  5

void setupChannelStateData()
{
  int i;
  for (i = 0; i < 16; i++) {
    gFreqOfChannel[i] = 1000;
    gRetainTimeOfChannel[i] =  gFreqOfChannel[i];
    gPulseTimeOfChannel[i] = gRetainTimeOfChannel[i]/10;//PCPULSELENGTH;
    gDuTimeOfChannel[i] = 0-1;
    gRetainDuTimeOfChannel[i] = 0-1;
    gMutedOfChannel[i] = false;

  }
}


void  setChannelData( int ch, int f )
{
  gFreqOfChannel[ch] = f;
  gRetainTimeOfChannel[ch] = gFreqOfChannel[ch];
  gPulseTimeOfChannel[ch] = gRetainTimeOfChannel[ch]/10;//PCPULSELENGTH;
}

void  playChannelData()
{
  for (int i = 2; i < 14; i++) {
    if (gPulseTimeOfChannel[i] == 0) {
      turnoff(i);

    }
    else if (gRetainTimeOfChannel[i] == 0) {
      // new pulse
      //Serial.print("\r\nplayChannelData");
      //Serial.print(gFreqOfChannel[i]);
      if (0 < gFreqOfChannel[i] && gFreqOfChannel[i] < 500) {      //for safety
        gRetainTimeOfChannel[i] = gFreqOfChannel[i];
        gPulseTimeOfChannel[i] = gRetainTimeOfChannel[i]/10;//PCPULSELENGTH;
        if (!gMutedOfChannel[i]) {
          turnon(i);
        }
      }
      else{
        turnoff(i);
      }
    }//else{
    gRetainTimeOfChannel[i]--;
    gPulseTimeOfChannel[i]--;
    if (gMutedOfChannel[i] && (gChannelStates[i] == DWON)) {
      turnoff(i);
    }

    //}
  }
}


void  turnon(int ch)
{
  digitalWrite(ch, HIGH);
  gChannelStates[ch] = DWON;
}
void  turnoff(int ch)
{
  digitalWrite(ch, LOW);
  gChannelStates[ch] = DWOFF;
}


void initDW()
{
  int i;
  for (i = 2; i < 14; i++) {
    pinMode(i, OUTPUT);
    turnoff(i);
  }
  gMode = DWSELFCHECK;
}

void  resetDW()
{
  int i;
  for (i = 2; i < 14; i++) {
    turnoff(i);
  }
}



#define  TBINTERVAL  200
#define  TBLENGTH  5

void  testblink()
{
  static int state = 0;

  if (state == 0) {
    for (int i = 2; i < 14; i++) {
      turnon(i);
    }
    state = TBINTERVAL;
  }
  else{
    if (state == (TBINTERVAL - TBLENGTH)) {
      for (int i = 2; i < 14; i++) {
        turnoff(i);
      }
    }
    state--;
  }
}

void  selfcheck()
{
  testblink();
}

unsigned long gPrevTime ;

void setup()
{
  Serial.begin(115200);
  Serial.print("\r\nStart");
  // noInterrupts();

  initDW();
  setupChannelStateData();
  acc.powerOn();
  gPrevTime = micros(); // 70 minutes
}

void loop()
{
  byte err;
  static byte msg[8];
  static int newmode = DWSELFCHECK;
  static boolean  connected = false;
  static  boolean muted = false;

  unsigned long currtime = micros();
  unsigned long intervalTime = currtime - gPrevTime;

  if (acc.isConnected()) {
    if (!connected) {
      connected = true;
      Serial.print("\r\nConnected");
    }
    int len = acc.read(msg, 1, 1);
    while (len > 0) {
      switch (msg[0]) {
      case DWTURNON:
        break;
      case DWTURNOFF:
        break;
      case DWCHANGEMODE:
        {
          Serial.print("\r\nDWCHANGEMODE");
          len = acc.read(msg, 1, USB_NAK_LIMIT);
          if (len > 0) {
            newmode = msg[0] ;
            //if (newmode != gMode) {
            resetDW();
            //muted = false;
            switch (newmode) {
            case DWSELFCHECK:
            default:
              Serial.print("\r\nDWSELFCHECK");
              break;
            case DWAUTOPLAY:
              Serial.print("\r\nDWAUTOPLAY");
              break;
            case MANUALPLAY:
              Serial.print("\r\nMANUALPLAY");
              break;
            case RECORDPALY:
              Serial.print("\r\nRECORDPALY");
              break;
            case DWSTOP:
              Serial.print("\r\nDWSTOP");
              break;
            }
            //}
            if (gMode != newmode) {
              gMode = newmode;
            }
          }
        }
        break;
      case DWMUTE:
        Serial.print("\r\nDWMUTE");
        muted = true;
        break;
      case DWUNMUTE:
        Serial.print("\r\nDWUNMUTE");
        muted = false;
        break;
      case DWSETCHANNELFEREQ:
        {
          len = acc.read(msg, 7, USB_NAK_LIMIT);
          if (len == 7) {
            Serial.print("\r\nDWSETCHANNELFEREQ");

            int ch = msg[0] ;
            int  freq = (msg[1] << 8) + msg[2];
            //Serial.print(ch);
            //Serial.print("\r\n");
            Serial.print(freq);
            //Serial.print("\r\n");
            turnoff(ch);
            setChannelData(ch, freq);
          }
        }
        break;
      }
      len = acc.read(msg, 1, 1);
    }
  }
  else{
    if (connected) {
      Serial.print("\r\nDisconnected");
      resetDW();
      gMode = DWSELFCHECK;
      connected = false;
    }

  }

  if (!muted) {
    switch (gMode) {
    case DWSELFCHECK:
    default:
      selfcheck();
      break;
    case DWAUTOPLAY:
      playChannelData();
      break;
    case MANUALPLAY:
      playChannelData();
      break;
    case RECORDPALY:
      break;
    case DWSTOP:
      break;
    }
  }

  currtime = micros();
  intervalTime = currtime - gPrevTime;
  gPrevTime = currtime;

  unsigned long dtime = (1000 - intervalTime);
  if (1000 < dtime) {
    dtime = 500;
  }
  delayMicroseconds(dtime);
}

















